home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 176-200 / disk_195 / microemacs / src.zoo / vms.c < prev    next >
C/C++ Source or Header  |  1989-03-23  |  33KB  |  1,214 lines

  1. /*
  2.  *  Advanced VMS terminal driver
  3.  *
  4.  *  Consults the system's terminal tables for both DEC terminals,
  5.  *  foreign and user defined terminals.
  6.  *
  7.  *  Author:  Curtis Smith
  8.  *  Update history:
  9.  *    14-Jul-1987, first revision.
  10.  *    02-Jan-1988, by J. A. Lomicka: Code addition for interpreting
  11.  *        LK201 function keys, application keypad and cursor
  12.  *        position reports.
  13.  *    09-Apr-1988, second revision.
  14.  *        Major changes:
  15.  *        1) H files removed; replaced with globalvalues.
  16.  *        2) Terminal now left in ECHO mode. Read call
  17.  *        disables echo.
  18.  *        3) TYPAHD macro now performs correctly.
  19.  *        4) $sres variable now accepts NORMAL and WIDE.
  20.  *        5) Writes to screen now use QIO without waiting.
  21.  *        This gives a slight increase in performance.
  22.  *        Had to make some QIOW a different event flag number.
  23.  *        6) Function keys, special keys and arrow keys
  24.  *        are now bound using the following table:
  25.  *            FNa-DOWN FNn-5    FN0-     FNA-F10  FNN-E1
  26.  *            FNb-LEFT FNo-6    FN1-F1   FNB-F11  FNO-E2
  27.  *            FNc-RITE FNp-7    FN2-F2   FNC-F12  FNP-E3
  28.  *            FNd-UP   FNq-8    FN3-F3   FND-F13  FNQ-E4
  29.  *            FNe-PF1  FNr-9    FN4-F4   FNE-F14  FNR-E5
  30.  *            FNf-PF2  FNs-.    FN5-F5   FNF-F15  FNS-E6
  31.  *            FNg-PF3  FNt-ENT  FN6-F6   FNG-F16  FNT-
  32.  *            FNh-PF4  FNu-,    FN7-F7   FNH-F17  FNU-
  33.  *            FNi-0    FNv--    FN8-F8   FNI-F18  FNV-
  34.  *            FNj-1    FNw-     FN9-F9   FNJ-F19  FNW-
  35.  *            FNk-2    FNx-              FNK-F20  FNX-
  36.  *            FNl-3    FNy-              FNL-     FNY-
  37.  *            FNm-4    FNz-              FNM-     FNZ-
  38.  *        See ebind.h for key bindings.
  39.  *    2-dec-88 Curtis Smith
  40.  *    - These have been rebound to the new machine independant bindings
  41.  */
  42.  
  43. /** Standard include files **/
  44. #include <stdio.h>            /* Standard I/O package        */
  45. #include "estruct.h"            /* Emacs' structures        */
  46. #include "etype.h"
  47. #include "edef.h"            /* Emacs' definitions        */
  48. #include    "elang.h"
  49.  
  50. #if    VMS
  51. /***
  52.  *  nothing  -  The nothing function.
  53.  *
  54.  *  This function is used as a placeholder for unimplemented functions,
  55.  *  or to compile an empty module (which VMS doesn't like).
  56.  *
  57.  *  Nothing returned.
  58.  ***/
  59. nothing()
  60. {
  61.     /* Nothing */
  62. }
  63.  
  64. #if VMSVT
  65.  
  66. /** Parameters **/
  67. #define NKEYENT        128        /* Number of keymap entries    */
  68.  
  69. /** VMS's include files **/
  70. #include <descrip.h>            /* Descriptor definitions    */
  71.  
  72. /** VMS's global values **/
  73. globalvalue IO$M_NOECHO;        /* Suppress echo on read    */
  74. globalvalue IO$M_NOFORMAT;        /* Suppress formatting on write    */
  75. globalvalue IO$M_TIMED;            /* Timeout on input        */
  76. globalvalue IO$M_TYPEAHDCNT;        /* Get typeahead count        */
  77. globalvalue IO$_READLBLK;        /* Read logical block        */
  78. globalvalue IO$_SENSEMODE;        /* Sense mode of terminal    */
  79. globalvalue IO$_SETMODE;        /* Set mode of terminal        */
  80. globalvalue IO$_WRITELBLK;        /* Write logical block        */
  81. globalvalue SMG$K_BEGIN_REVERSE;    /* Begin reverse video        */
  82. globalvalue SMG$K_COLUMNS;        /* Number of columns narrow    */
  83. globalvalue SMG$K_END_REVERSE;        /* End reverse video        */
  84. globalvalue SMG$K_ERASE_TO_END_LINE;    /* Erase to end of line        */
  85. globalvalue SMG$K_ERASE_WHOLE_DISPLAY;    /* Erase entire screen        */
  86. globalvalue SMG$K_KEY_0;        /* 0 key            */
  87. globalvalue SMG$K_KEY_1;        /* 1 key            */
  88. globalvalue SMG$K_KEY_2;        /* 2 key            */
  89. globalvalue SMG$K_KEY_3;        /* 3 key            */
  90. globalvalue SMG$K_KEY_4;        /* 4 key            */
  91. globalvalue SMG$K_KEY_5;        /* 5 key            */
  92. globalvalue SMG$K_KEY_6;        /* 6 key            */
  93. globalvalue SMG$K_KEY_7;        /* 7 key            */
  94. globalvalue SMG$K_KEY_8;        /* 8 key            */
  95. globalvalue SMG$K_KEY_9;        /* 9 key            */
  96. globalvalue SMG$K_KEY_COMMA;        /* Comma key            */
  97. globalvalue SMG$K_KEY_DOWN_ARROW;    /* Down arrow key        */
  98. globalvalue SMG$K_KEY_ENTER;        /* Enter key            */
  99. globalvalue SMG$K_KEY_E1;        /* E1 key            */
  100. globalvalue SMG$K_KEY_E2;        /* E2 key            */
  101. globalvalue SMG$K_KEY_E3;        /* E3 key            */
  102. globalvalue SMG$K_KEY_E4;        /* E4 key            */
  103. globalvalue SMG$K_KEY_E5;        /* E5 key            */
  104. globalvalue SMG$K_KEY_E6;        /* E6 key            */
  105. globalvalue SMG$K_KEY_F1;        /* F1 key            */
  106. globalvalue SMG$K_KEY_F2;        /* F2 key            */
  107. globalvalue SMG$K_KEY_F3;        /* F3 key            */
  108. globalvalue SMG$K_KEY_F4;        /* F4 key            */
  109. globalvalue SMG$K_KEY_F5;        /* F5 key            */
  110. globalvalue SMG$K_KEY_F6;        /* F6 key            */
  111. globalvalue SMG$K_KEY_F7;        /* F7 key            */
  112. globalvalue SMG$K_KEY_F8;        /* F8 key            */
  113. globalvalue SMG$K_KEY_F9;        /* F9 key            */
  114. globalvalue SMG$K_KEY_F10;        /* F10 key            */
  115. globalvalue SMG$K_KEY_F11;        /* F11 key            */
  116. globalvalue SMG$K_KEY_F12;        /* F12 key            */
  117. globalvalue SMG$K_KEY_F13;        /* F13 key            */
  118. globalvalue SMG$K_KEY_F14;        /* F14 key            */
  119. globalvalue SMG$K_KEY_F15;        /* F15 key            */
  120. globalvalue SMG$K_KEY_F16;        /* F16 key            */
  121. globalvalue SMG$K_KEY_F17;        /* F17 key            */
  122. globalvalue SMG$K_KEY_F18;        /* F18 key            */
  123. globalvalue SMG$K_KEY_F19;        /* F19 key            */
  124. globalvalue SMG$K_KEY_F20;        /* F20 key            */
  125. globalvalue SMG$K_KEY_LEFT_ARROW;    /* Left arrow key        */
  126. globalvalue SMG$K_KEY_MINUS;        /* Minus key            */
  127. globalvalue SMG$K_KEY_PERIOD;        /* Period key            */
  128. globalvalue SMG$K_KEY_PF1;        /* PF1 key            */
  129. globalvalue SMG$K_KEY_PF2;        /* PF2 key            */
  130. globalvalue SMG$K_KEY_PF3;        /* PF3 key            */
  131. globalvalue SMG$K_KEY_PF4;        /* PF4 key            */
  132. globalvalue SMG$K_KEY_RIGHT_ARROW;    /* Right arrow key        */
  133. globalvalue SMG$K_KEY_UP_ARROW;        /* Up arrow key            */
  134. globalvalue SMG$K_SET_CURSOR_ABS;    /* Set cursor            */
  135. globalvalue SMG$K_WIDE_SCREEN_COLUMNS;    /* Number of columns wide    */
  136. globalvalue SMG$K_WIDTH_NARROW;        /* Set terminal to narrow mode    */
  137. globalvalue SMG$K_WIDTH_WIDE;        /* Set terminal to wide mode    */
  138. globalvalue SS$_TIMEOUT;        /* Status if read timed-out    */
  139. globalvalue TT2$M_PASTHRU;        /* Passthru mode in t_extend    */
  140.  
  141. /** I/O information block definitions **/
  142. struct iosb {                /* I/O status block        */
  143.     short i_cond;            /* Condition value        */
  144.     short i_xfer;            /* Transfer count        */
  145.     long i_info;            /* Device information        */
  146. };
  147. struct termchar {            /* Terminal characteristics    */
  148.     char t_class;            /* Terminal class        */
  149.     char t_type;            /* Terminal type        */
  150.     short t_width;            /* Terminal width in characters    */
  151.     long t_mandl;            /* Terminal's mode and length    */
  152.     long t_extend;            /* Extended characteristics    */
  153. };
  154. struct tahd {                /* Typeahead count        */
  155.     short t_count;            /* Number of character waiting    */
  156.     char t_first;            /* Next character available    */
  157.     char t_resv1;            /* Reserved by DEC        */
  158.     long t_resv2;            /* Reserved by DEC        */
  159. };
  160.  
  161. /** Type definitions **/
  162. struct keyent {                /* Key mapping entry        */
  163.     struct keyent * samlvl;        /* Character on same level    */
  164.     struct keyent * nxtlvl;        /* Character on next level    */
  165.     char ch;            /* Character            */
  166.     int code;            /* Resulting keycode        */
  167. };
  168.  
  169. /** Command success **/
  170. #define SUCCESS(x)    ((x)&1)        /* TRUE if successful        */
  171. #define FAILURE(x)    (((x)&1)==0)    /* TRUE if unsuccessful        */
  172.  
  173. /** Values to manage the screen **/
  174. static int termtype;            /* Handle to pass to SMG    */
  175. static short channel;            /* Terminal I/O channel        */
  176. static struct termchar oldmode;        /* Old terminal modes        */
  177. static struct termchar newmode;        /* New terminal modes        */
  178. static char * begin_reverse;        /* Begin reverse video        */
  179. static char * end_reverse;        /* End reverse video        */
  180. static char * erase_to_end_line;    /* Erase to end of line        */
  181. static char * erase_whole_display;    /* Erase whole display        */
  182. static char * width_narrow;        /* Set narrow size screen    */
  183. static char * width_wide;        /* Set wide size screen        */
  184. static int narrow_char;            /* Number of characters narrow    */
  185. static int wide_char;            /* Number of characters wide    */
  186. static char inbuf[64];            /* Input buffer            */
  187. static char * inbufh = inbuf;        /* Head of input buffer        */
  188. static char * inbuft = inbuf;        /* Tail of input buffer        */
  189. static char outbuf[1024];        /* Output buffer        */
  190. static char * outbuft = outbuf;        /* Tail of output buffer    */
  191. static char keyseq[256];        /* Prefix escape sequence table    */
  192. static struct keyent keymap[NKEYENT];    /* Key map            */
  193. static struct keyent * nxtkey = keymap;    /* Next free key entry        */
  194.  
  195. /** Forward references **/
  196. int vmsopen(), vmsclose(), vmsgetc(), vmsputc(), vmsflush();
  197. int vmsmove(), vmseeol(), vmseeop(), vmsbeep(), vmsrev(), vmscres();
  198.  
  199. /** Terminal dispatch table **/
  200. TERM term = {
  201.     72 - 1,                /* Max number of rows allowable */
  202.     /* Filled in */ - 1,        /* Current number of rows used    */
  203.     160,                /* Max number of columns    */
  204.     /* Filled in */ 0,        /* Current number of columns    */
  205.     64,                /* Min margin for extended lines*/
  206.     8,                /* Size of scroll region    */
  207.     100,                /* # times thru update to pause */
  208.     vmsopen,            /* Open terminal at the start    */
  209.     vmsclose,            /* Close terminal at end    */
  210.     nothing,            /* Open keyboard        */
  211.     nothing,            /* Close keyboard        */
  212.     vmsgetc,            /* Get character from keyboard    */
  213.     vmsputc,            /* Put character to display    */
  214.     vmsflush,            /* Flush output buffers        */
  215.     vmsmove,            /* Move cursor, origin 0    */
  216.     vmseeol,            /* Erase to end of line        */
  217.     vmseeop,            /* Erase to end of page        */
  218.     vmsbeep,            /* Beep                */
  219.     vmsrev,                /* Set reverse video state    */
  220.     vmscres                /* Change screen resolution    */
  221. #if COLOR
  222.     ,
  223.     nothing,            /* Set forground color        */
  224.     nothing                /* Set background color        */
  225. #endif /* COLOR */
  226. };
  227.  
  228. /***
  229.  *  vmsmove  -  Move the cursor (0 origin)
  230.  *
  231.  *  vmsmove calls to the SMG run-time library to produce a character
  232.  *  sequence to position the cursor.  If the sequence cannot be made,
  233.  *  a string "OOPS" is produced instead, much like the termcap library
  234.  *  under UNIX.  In the case of "OOPS", the user will soon know that
  235.  *  his terminal entry is incorrect.
  236.  *
  237.  *  Nothing returned.
  238.  ***/
  239. vmsmove(row, column)
  240. int row;                /* Row position            */
  241. int column;                /* Column position        */
  242. {
  243.     char buffer[32];
  244.     int rlen, status;
  245.     
  246.     static int code = SMG$K_SET_CURSOR_ABS;
  247.     static int len = sizeof(buffer);
  248.     static int arg[3] = { 2 };
  249.  
  250.     /* SMG assumes the row/column positions    are 1 based. */
  251.     arg[1] = row + 1;
  252.     arg[2] = column + 1;
  253.  
  254.     /* Call to SMG for the sequence */
  255.     status = SMG$GET_TERM_DATA(&termtype, &code, &len, &rlen, buffer, arg);
  256.     if (SUCCESS(status)) {
  257.         buffer[rlen] = '\0';
  258.         vmsputs(buffer);
  259.     } else
  260.         vmsputs("OOPS");
  261. }
  262.  
  263. /***
  264.  *  vmscres  -  Change screen resolution
  265.  *
  266.  *  vmscres changes the screen resolution of the current window.
  267.  *  Allowable sizes are NORMAL and WIDE.
  268.  *
  269.  *  Nothing returned
  270.  ***/
  271. vmscres(value)
  272. char * value;                /* Value to set            */
  273. {
  274.     int width;
  275.  
  276.     /* Skip if not supported */
  277.     if (width_wide == NULL || width_narrow == NULL)
  278.         return;
  279.  
  280.     /* Check value */
  281.     if (strcmp(value, "WIDE") == 0) {
  282.         width = wide_char;
  283.         vmsputs(width_wide);
  284.     } else if (strcmp(value, "NORMAL") == 0) {
  285.         width = narrow_char;
  286.         vmsputs(width_narrow);
  287.     }
  288.  
  289.     /* Change width */
  290.     oldmode.t_width = newmode.t_width = width;
  291.     newwidth(TRUE, width);
  292.  
  293.     /* Set resolution variable */
  294.     strcpy(sres, value);
  295. }
  296.  
  297. /***
  298.  *  vmsrev  -  Set the reverse video status
  299.  *
  300.  *  vmsrev either sets or resets the reverse video state, based on the
  301.  *  boolean argument.  This function is only called if the revexist
  302.  *  boolean variable is set to TRUE.  Otherwise there is no reverse
  303.  *  video available.
  304.  *
  305.  *  Nothing returned.
  306.  ***/
  307. vmsrev(status)
  308. int status;                /* TRUE if setting reverse    */
  309. {
  310.     vmsputs(status ? begin_reverse : end_reverse);
  311. }
  312.  
  313. /***
  314.  *  vmseeol  -  Erase to end of line
  315.  *
  316.  *  When this function is called, the lines worth of text after the
  317.  *  cursor is erased.  This function is only called if the eolexist
  318.  *  boolean variable is set to TRUE.  Otherwise the display manager
  319.  *  will produce enough spaces to erase the line.
  320.  *
  321.  *  Nothing returned.
  322.  ***/
  323. vmseeol()
  324. {
  325.     vmsputs(erase_to_end_line);
  326. }
  327.  
  328. /***
  329.  *  vmseeop  -  Erase to end of page (clear screen)
  330.  *
  331.  *  vmseeop really should be called vmsclear because it really should
  332.  *  be an erase screen function.  When called, this routine will send
  333.  *  the erase entire screen sequence to the output.
  334.  *
  335.  *  Nothing returned.
  336.  ***/
  337. vmseeop()
  338. {
  339.     vmsputs(erase_whole_display);
  340. }
  341.  
  342. /***
  343.  *  vmsbeep  -  Ring the bell
  344.  *
  345.  *  vmsbeep send a bell character to the output.  It might be possible
  346.  *  in the future to include the NOISY definition and attempt to flash
  347.  *  the screen, perhaps using LIGHT_SCREEN and DARK_SCREEN.
  348.  *
  349.  *  Nothing returned.
  350.  ***/
  351. vmsbeep()
  352. {
  353.     vmsputc('\007');
  354. }
  355.  
  356. /***
  357.  *  vmsgetstr  -  Get an SMG string capability by name
  358.  *
  359.  *  vmsgetstr attempts to obtain the escape sequence for a particular
  360.  *  job from the SMG library.  Most sequences do not require a parameter
  361.  *  with the sequence, others do.  In order to obtain the definition
  362.  *  without knowing ahead of time whether ornot the definition has a
  363.  *  parameter, we call SMG once with a parameter and if that fails, we
  364.  *  try again without one.  If both attempts fail, we will return the
  365.  *  NULL string.
  366.  *
  367.  *  Storage for the sequence comes from a local pool.
  368.  *
  369.  *  Returns:    Escape sequence
  370.  *        NULL    No escape sequence available
  371.  ***/ 
  372. char * vmsgetstr(code)
  373. int code;                /* Request code            */
  374. {
  375.     char * result;
  376.     int rlen, status;
  377.     
  378.     static char seq[1024];
  379.     static char * buffer = seq;
  380.     static int len = sizeof(seq);
  381.     static int arg[2] = { 1, 1 };
  382.  
  383.     /* Get sequence with one parameter */
  384.     status = SMG$GET_TERM_DATA(&termtype, &code, &len, &rlen, buffer, arg);
  385.     if (FAILURE(status)) {
  386.         /* Try again with zero parameters */
  387.         status = SMG$GET_TERM_DATA(&termtype, &code, &len, &rlen, buffer);
  388.         if (FAILURE(status))
  389.             return NULL;
  390.     }
  391.  
  392.     /* Check for empty result */
  393.     if (rlen == 0)
  394.         return NULL;
  395.     
  396.     /* Save current position so we can return it to caller */
  397.     result = buffer;
  398.     buffer[rlen++] = '\0';
  399.     buffer += rlen;
  400.  
  401.     /* Return capability to user */
  402.     return result;
  403. }
  404.  
  405. /***
  406.  *  vmsgetnum  -  Get numerical constant from SMG
  407.  *
  408.  *  vmsgetnum attempts to get a numerical constant from the SMG package.
  409.  *  If the constant cannot be found, -1 is returned.
  410.  ***/
  411. int vmsgetnum(code)
  412. int code;                /* SMG code            */
  413. {
  414.     int status, result;
  415.  
  416.     /* Call SMG for code translation */
  417.     status = SMG$GET_NUMERIC_DATA(&termtype, &code, &result);
  418.     return FAILURE(status) ? -1 : result;
  419. }
  420.  
  421. /***
  422.  *  vmsaddkey  -  Add key to key map
  423.  *
  424.  *  vmsaddkey adds a new escape sequence to the sequence table.
  425.  *  I am not going to try to explain this table to you in detail.
  426.  *  However, in short, it creates a tree which can easily be transversed
  427.  *  to see if input is in a sequence which can be translated to a
  428.  *  function key (arrows and find/select/do etc. are treated like
  429.  *  function keys).  If the sequence is ambiguous or duplicated,
  430.  *  it is silently ignored.
  431.  *
  432.  *  Nothing returned
  433.  ***/
  434. vmsaddkey(code, fn)
  435. int code;                /* SMG key code            */
  436. int fn;                /* Resulting keycode        */
  437. {
  438.     char * seq;
  439.     int first;
  440.     struct keyent * cur, * nxtcur;
  441.     
  442.     /* Skip on NULL sequence */
  443.     seq = vmsgetstr(code);
  444.     if (seq == NULL)
  445.         return;
  446.     
  447.     /* If no keys defined, go directly to insert mode */
  448.     first = 1;
  449.     if (nxtkey != keymap) {
  450.         
  451.         /* Start at top of key map */
  452.         cur = keymap;
  453.         
  454.         /* Loop until matches exhast */
  455.         while (*seq) {
  456.             
  457.             /* Do we match current character */
  458.             if (*seq == cur->ch) {
  459.                 
  460.                 /* Advance to next level */
  461.                 seq++;
  462.                 cur = cur->nxtlvl;
  463.                 first = 0;
  464.             } else {
  465.                 
  466.                 /* Try next character on same level */
  467.                 nxtcur = cur->samlvl;
  468.                 
  469.                 /* Stop if no more */
  470.                 if (nxtcur)
  471.                     cur = nxtcur;
  472.                 else
  473.                     break;
  474.             }
  475.         }
  476.     }
  477.     
  478.     /* Check for room in keymap */
  479.     if (strlen(seq) > NKEYENT - (nxtkey - keymap))
  480.         return;
  481.         
  482.     /* If first character if sequence is inserted, add to prefix table */
  483.     if (first)
  484.         keyseq[(unsigned char) *seq] = 1;
  485.         
  486.     /* If characters are left over, insert them into list */
  487.     for (first = 1; *seq; first = 0) {
  488.         
  489.         /* Make new entry */
  490.         nxtkey->ch = *seq++;
  491.         nxtkey->code = fn;
  492.         
  493.         /* If root, nothing to do */
  494.         if (nxtkey != keymap) {
  495.             
  496.             /* Set first to samlvl, others to nxtlvl */
  497.             if (first)
  498.                 cur->samlvl = nxtkey;
  499.             else
  500.                 cur->nxtlvl = nxtkey;
  501.         }
  502.  
  503.         /* Advance to next key */
  504.         cur = nxtkey++;
  505.     }
  506. }
  507.  
  508. /***
  509.  *  vmscap  -  Get capabilities from VMS's SMG library
  510.  *
  511.  *  vmscap retrives all the necessary capabilities from the SMG
  512.  *  library to operate microEmacs.  If an insufficent number of
  513.  *  capabilities are found for the particular terminal, an error
  514.  *  status is returned.
  515.  *
  516.  *  Returns:    0 if okay, <>0 if error
  517.  ***/
  518. int vmscap()
  519. {
  520.     char * set_cursor_abs;
  521.     int status;
  522.     
  523.     /* Start SMG package */
  524.     status = SMG$INIT_TERM_TABLE_BY_TYPE(&oldmode.t_type, &termtype);
  525.     if (FAILURE(status)) {
  526.         printf(TEXT189);
  527. /*                     "Cannot find entry for terminal type.\n" */
  528.         printf(TEXT190);
  529. /*                     "Check terminal type with \"SHOW TERMINAL\" or\n" */
  530.         printf(TEXT191);
  531. /*                     "try setting with \"SET TERMINAL/INQUIRE\"\n" */
  532.         return 1;
  533.     }
  534.         
  535.     /* Get reverse video */
  536.     begin_reverse = vmsgetstr(SMG$K_BEGIN_REVERSE);
  537.     end_reverse = vmsgetstr(SMG$K_END_REVERSE);
  538.     revexist = begin_reverse != NULL && end_reverse != NULL;
  539.     
  540.     /* Get erase to end of line */
  541.     erase_to_end_line = vmsgetstr(SMG$K_ERASE_TO_END_LINE);
  542.     eolexist = erase_to_end_line != NULL;
  543.     
  544.     /* Get more neat stuff */
  545.     erase_whole_display = vmsgetstr(SMG$K_ERASE_WHOLE_DISPLAY);
  546.     width_wide = vmsgetstr(SMG$K_WIDTH_WIDE);
  547.     width_narrow = vmsgetstr(SMG$K_WIDTH_NARROW);
  548.     narrow_char = vmsgetnum(SMG$K_COLUMNS);
  549.     wide_char = vmsgetnum(SMG$K_WIDE_SCREEN_COLUMNS);
  550.     set_cursor_abs = vmsgetstr(SMG$K_SET_CURSOR_ABS);
  551.  
  552.     /* Disable resoultion if unreasonable */
  553.     if (narrow_char < 10 || wide_char < 10) {
  554.         width_wide = width_narrow = NULL;
  555.         strcpy(sres, "NORMAL");
  556.     } else
  557.         /* Kludge resolution */
  558.         strcpy(sres, oldmode.t_width == wide_char ? "WIDE" : "NORMAL");
  559.  
  560.     /* Check for minimal operations */
  561.     if (set_cursor_abs == NULL || erase_whole_display == NULL) {
  562.         printf(TEXT192);
  563. /*                     "The terminal type does not have enough power to run\n" */
  564.         printf(TEXT193);
  565. /*                     "MicroEMACS.  Try a different terminal or check\n" */
  566.         printf(TEXT194);
  567. /*                     "type with \"SHOW TERMINAL\".\n" */
  568.         return 1;
  569.     }
  570.     
  571.     /* Add function keys to keymapping table */
  572.     vmsaddkey(SMG$K_KEY_DOWN_ARROW, 'N');
  573.     vmsaddkey(SMG$K_KEY_LEFT_ARROW, 'B');
  574.     vmsaddkey(SMG$K_KEY_RIGHT_ARROW, 'F');
  575.     vmsaddkey(SMG$K_KEY_UP_ARROW, 'P');
  576.     vmsaddkey(SMG$K_KEY_PF1, '1');
  577.     vmsaddkey(SMG$K_KEY_PF2, '2');
  578.     vmsaddkey(SMG$K_KEY_PF3, '3');
  579.     vmsaddkey(SMG$K_KEY_PF4, '4');
  580.     vmsaddkey(SMG$K_KEY_0, ALTD | '0');
  581.     vmsaddkey(SMG$K_KEY_1, ALTD | '1');
  582.     vmsaddkey(SMG$K_KEY_2, ALTD | '2');
  583.     vmsaddkey(SMG$K_KEY_3, ALTD | '3');
  584.     vmsaddkey(SMG$K_KEY_4, ALTD | '4');
  585.     vmsaddkey(SMG$K_KEY_5, ALTD | '5');
  586.     vmsaddkey(SMG$K_KEY_6, ALTD | '6');
  587.     vmsaddkey(SMG$K_KEY_7, ALTD | '7');
  588.     vmsaddkey(SMG$K_KEY_8, ALTD | '8');
  589.     vmsaddkey(SMG$K_KEY_9, ALTD | '9');
  590.     vmsaddkey(SMG$K_KEY_PERIOD, SHFT|'.');
  591.     vmsaddkey(SMG$K_KEY_ENTER, SHFT|CTRL|'M');
  592.     vmsaddkey(SMG$K_KEY_COMMA, SHFT|',');
  593.     vmsaddkey(SMG$K_KEY_MINUS, SHFT|'-');
  594.     vmsaddkey(SMG$K_KEY_F1, '1');
  595.     vmsaddkey(SMG$K_KEY_F2, '2');
  596.     vmsaddkey(SMG$K_KEY_F3, '3');
  597.     vmsaddkey(SMG$K_KEY_F4, '4');
  598.     vmsaddkey(SMG$K_KEY_F5, '5');
  599.     vmsaddkey(SMG$K_KEY_F6, '6');
  600.     vmsaddkey(SMG$K_KEY_F7, '7');
  601.     vmsaddkey(SMG$K_KEY_F8, '8');
  602.     vmsaddkey(SMG$K_KEY_F9, '9');
  603.     vmsaddkey(SMG$K_KEY_F10, '0');
  604.     vmsaddkey(SMG$K_KEY_F11, SHFT | '1');
  605.     vmsaddkey(SMG$K_KEY_F12, SHFT | '2');
  606.     vmsaddkey(SMG$K_KEY_F13, SHFT | '3');
  607.     vmsaddkey(SMG$K_KEY_F14, SHFT | '4');
  608.     vmsaddkey(SMG$K_KEY_F15, SHFT | '5');
  609.     vmsaddkey(SMG$K_KEY_F16, SHFT | '6');
  610.     vmsaddkey(SMG$K_KEY_F17, SHFT | '7');
  611.     vmsaddkey(SMG$K_KEY_F18, SHFT | '8');
  612.     vmsaddkey(SMG$K_KEY_F19, SHFT | '9');
  613.     vmsaddkey(SMG$K_KEY_F20, SHFT | '0');
  614.     vmsaddkey(SMG$K_KEY_E1, CTRL | 'S');
  615.     vmsaddkey(SMG$K_KEY_E2, 'C');
  616.     vmsaddkey(SMG$K_KEY_E3, 'D');
  617.     vmsaddkey(SMG$K_KEY_E4, ALTD | 'S');
  618.     vmsaddkey(SMG$K_KEY_E5, 'Z');
  619.     vmsaddkey(SMG$K_KEY_E6, 'V');
  620.  
  621.     /* Everything okay */
  622.     return 0;
  623. }
  624.  
  625. /***
  626.  *  vmsgtty - Get terminal type from system control block
  627.  *
  628.  *  vmsgtty obtains the terminal's information such as flags modes,
  629.  *  baud rate, size etc. and stores it in the structure block.
  630.  *  If the block cannot be obtainedm, an error condition is returned.
  631.  *
  632.  *  Returns:    Status
  633.  ***/
  634. int vmsgtty(tc)
  635. struct termchar * tc;            /* Terminal characteristics    */
  636. {
  637.     int status;
  638.     struct iosb io;
  639.     
  640.     /* Get terminal characteristics */
  641.     status = SYS$QIOW(1, channel, IO$_SENSEMODE, &io, 0, 0,
  642.         tc, sizeof(*tc), 0, 0, 0, 0);
  643.     
  644.     /* Check status */
  645.     return FAILURE(status) && FAILURE(io.i_cond);
  646. }
  647.  
  648. /***
  649.  *  vmsstty - Set terminal control block
  650.  *
  651.  *  vmsstty takes a previous vmsgtty with modifications, and stores
  652.  *  this as the current terminal control block.
  653.  *
  654.  *  Returns:    Status
  655.  ***/
  656. int vmsstty(tc)
  657. struct termchar * tc;            /* Terminal characteristics    */
  658. {
  659.     int status;
  660.     struct iosb io;
  661.     
  662.     /* Set terminal characteristics */
  663.     status = SYS$QIOW(1, channel, IO$_SETMODE, &io, 0, 0,
  664.         tc, sizeof(*tc), 0, 0, 0, 0);
  665.     
  666.     /* Check status */
  667.     return FAILURE(status) && FAILURE(io.i_cond);
  668. }
  669.  
  670. /***
  671.  *  vmsclose  -  Close the connection to the terminal
  672.  *
  673.  *  vmsclose resets the terminal to the original state and cuts the
  674.  *  connection.  No further operations should be done after closing.
  675.  *
  676.  *  Nothing returned.
  677.  ***/
  678. vmsclose()
  679. {
  680.     /* Flush pending output */
  681.     vmsflush();
  682.  
  683.     /* Do this stupid thing for synchronization */
  684.     SYS$QIOW(1, channel, IO$_WRITELBLK | IO$M_NOFORMAT,
  685.         0, 0, 0, " \b", 2, 0, 0, 0, 0);
  686.  
  687.     /* Reset terminal to original modes */
  688.     vmsstty(&oldmode);
  689.     
  690.     /* Release channel */
  691.     SYS$DASSGN(channel);
  692. }
  693.  
  694. /***
  695.  *  vmsopen  -  Get terminal type and open terminal
  696.  *
  697.  *  Nothing returned
  698.  ***/
  699. vmsopen()
  700. {
  701.     $DESCRIPTOR(name, "TT");
  702.     int status;
  703.     
  704.     /* Open channel to terminal */
  705.     status = SYS$ASSIGN(&name, &channel, 0, 0);
  706.     if (FAILURE(status)) {
  707.         printf(TEXT195);
  708. /*                     "Cannot open channel to terminal.\n" */
  709.         exit(1);
  710.     }
  711.     
  712.     /* Get terminal type */
  713.     if (vmsgtty(&oldmode)) {
  714.         printf(TEXT196);
  715. /*                     "Cannot obtain terminal settings.\n" */
  716.         goto error;
  717.     }
  718.     
  719.     /* Get SMG */
  720.     if (vmscap())
  721.         goto error;
  722.     
  723.     /* Set sizes */
  724.     term.t_nrow = ((unsigned int) oldmode.t_mandl >> 24) - 1;
  725.     term.t_ncol = oldmode.t_width;
  726.  
  727.     /* Set new terminal modes */
  728.     newmode = oldmode;
  729.     newmode.t_extend |= TT2$M_PASTHRU;
  730.     if (vmsstty(&newmode)) {
  731.         printf(TEXT197);
  732. /*                     "Cannot modify terminal settings.\n" */
  733.         goto error;
  734.     }
  735.  
  736.     /* Finished! */
  737.     return;
  738.  
  739.     /* Make sure terminal deassigned */    
  740. error:
  741.     /* Release channel */
  742.     SYS$DASSGN(channel);
  743.     exit(1);
  744. }
  745.  
  746. /***
  747.  *  vmsflush  -  Flush output buffer
  748.  *
  749.  *  vmsflush causes all queued output characters to be written to the
  750.  *  terminal's screen.  We will use SYS$QIO because we don't need to
  751.  *  wait and because it dramaticly increases performance.
  752.  *
  753.  *  Nothing returned.
  754.  ***/
  755. vmsflush()
  756. {
  757.     int len;
  758.     
  759.     /* Compute size of request */
  760.     len = outbuft - outbuf;
  761.     
  762.     /* Skip if zero */
  763.     if (len) {
  764.         SYS$QIO(0, channel, IO$_WRITELBLK | IO$M_NOFORMAT,
  765.             0, 0, 0, outbuf, len, 0, 0, 0, 0);
  766.             
  767.         /* Reset buffer positions */
  768.         outbuft = outbuf;
  769.     }
  770. }
  771.  
  772. /***
  773.  *  vmsputc  -  Send a character to the screen
  774.  *
  775.  *  vmsputc queues character into a buffer for screen output.  When the
  776.  *  buffer is full the flush routine is called.  This is help speed
  777.  *  things up by avoiding millions of system calls.
  778.  *
  779.  *  Nothing returned.
  780.  ***/
  781. vmsputc(ch)
  782. char ch;                /* Character to add        */
  783. {
  784.     /* Check for overflow */
  785.     if (outbuft == &outbuf[sizeof(outbuf)])
  786.         vmsflush();
  787.         
  788.     /* Add character to buffer */
  789.     *outbuft++ = ch;
  790. }
  791.  
  792. /***
  793.  *  vmsputs  -  Send a string to vmsputc
  794.  *
  795.  *  vmsputs is a short-cut routine to handle sending a string of characters
  796.  *  to the character output routine.  A check is made for a NULL string,
  797.  *  while is considered valid.  A NULL string will produce no output.
  798.  *
  799.  *  Nothing returned.
  800.  ***/
  801. vmsputs(string)
  802. char * string;                /* String to write        */
  803. {
  804.     if (string)
  805.         while (*string)
  806.             vmsputc(*string++);
  807. }
  808.  
  809. /***
  810.  *  vmsgchar  -  Get character directly from VMS
  811.  *
  812.  *  vmsgchar is the lowest level of retrieving character from VMS.
  813.  *  The argument timed specifies where to wait for a character for
  814.  *  a short period (1 > wait >= 2 seconds) or indefinately.  The short
  815.  *  period version is used when obtaining a escape sequence.
  816.  *
  817.  *  Returns:  character or 0 if no character is available.
  818.  ***/
  819. char vmsgchar(timed)
  820. int timed;                /* TRUE if being timed        */
  821. {
  822.     char ch;
  823.     int status, op;
  824.     struct iosb io;
  825.     
  826.     /* Make operation */
  827.     op = (timed ? IO$M_TIMED : 0) | IO$_READLBLK | IO$M_NOECHO;
  828.     
  829.     /* Get next character */
  830.     status = SYS$QIOW(1, channel, op, &io, 0, 0, &ch, 1, 2, 0, 0, 0);
  831.         
  832.     /* Fatal error */
  833.     if (FAILURE(status) || FAILURE(io.i_cond)) {
  834.  
  835.         /* Check for time-out */
  836.         if (io.i_cond == SS$_TIMEOUT)
  837.             return 0;
  838.  
  839.         /* Real I/O error occured */
  840.         printf(TEXT198, status, io.i_cond);
  841. /*                     "I/O error (%d,%d)\n" */
  842.         SYS$DASSGN(channel);
  843.         exit(1);
  844.     }
  845.     
  846.     /* Return next character */
  847.     return ch;
  848. }
  849.  
  850. /***
  851.  *  vmsqin  -  Queue character for input
  852.  *
  853.  *  vmsqin queues the character into the input buffer for later
  854.  *  reading.  This routine will mostly be used by mouse support
  855.  *  and other escape sequence processing.
  856.  *
  857.  *  Nothing returned.
  858.  ***/
  859. vmsqin(ch)
  860. char ch;                /* Character to add        */
  861. {
  862.     /* Check for overflow */
  863.     if (inbuft == &inbuf[sizeof(inbuf)]) {
  864.         
  865.         /* Annoy user */
  866.         vmsbeep();
  867.         return;
  868.     }
  869.     
  870.     /* Add character */
  871.     *inbuft++ = ch;
  872. }
  873.  
  874. /***
  875.  *  vmsgcook  -  Get characters from input device
  876.  *
  877.  *  vmsgcook "cooks" input from the input device and places them into
  878.  *  the input queue.
  879.  *
  880.  *  Nothing returned.
  881.  ***/
  882. vmsgcook()
  883. {
  884.     char ch;
  885.     struct keyent * cur;
  886.     
  887.     /* Get first character untimed */
  888.     ch = vmsgchar(0);
  889.     vmsqin(ch);
  890.     
  891.     /* Skip if the key isn't a special leading escape sequence */
  892.     if (keyseq[(unsigned char) ch] == 0)
  893.         return;
  894.         
  895.     /* Start translating */
  896.     cur = keymap;
  897.     while (cur) {
  898.         if (cur->ch == ch) {
  899.             /* Is this the end */
  900.             if (cur->nxtlvl == NULL) {
  901.                 /* Replace all character with new sequence */
  902.                 inbuft = inbuf;
  903.                 vmsqin(0);
  904.                 vmsqin(cur->code);
  905.                 return;
  906.             } else {
  907.                 /* Advance to next level */
  908.                 cur = cur->nxtlvl;
  909.             
  910.                 /* Get next character, timed */
  911.                 ch = vmsgchar(1);
  912.                 if (ch == '\0')
  913.                     return;
  914.  
  915.                 /* Queue character */
  916.                 vmsqin(ch);
  917.             }
  918.         } else
  919.             /* Try next character on same level */
  920.             cur = cur->samlvl;
  921.     }
  922. }
  923.  
  924. /***
  925.  *  vmsgetc  -  Get a character
  926.  *
  927.  *  vmsgetc obtains input from the character input queue.  If the queue
  928.  *  is empty, a call to vmsgcook() is called to fill the input queue.
  929.  *
  930.  *  Returns:    character
  931.  ***/
  932. int vmsgetc()
  933. {
  934.     char ch;
  935.  
  936.     /* Loop until character found */
  937.     while (1) {
  938.     
  939.         /* Get input from buffer, if available */
  940.         if (inbufh != inbuft) {
  941.             ch = *inbufh++;
  942.             if (inbufh == inbuft)
  943.                 inbufh = inbuft = inbuf;
  944.             break;
  945.         } else
  946.     
  947.             /* Fill input buffer */
  948.             vmsgcook();
  949.     }
  950.     
  951.     /* Return next character */
  952.     return (int) ch;
  953. }
  954.  
  955. #if FLABEL
  956. /***
  957.  *  fnclabel  -  Label function keys
  958.  *
  959.  *  Currently, VMS does not have function key labeling.
  960.  *
  961.  *  Returns:    status.
  962.  ***/
  963. int fnclabel(flag, n)
  964. int flag;                /* TRUE if default        */
  965. int num;                /* Numerical argument        */
  966. {
  967.     /* On machines with no function keys...don't bother */
  968.     return TRUE;
  969. }
  970. #endif /* FLABEL */
  971.  
  972. /***
  973.  *  spal  -  Set palette type
  974.  *
  975.  *  spal sets the palette colors for the 8 colors available.  Currently,
  976.  *  there is nothing here, but some DEC terminals, (VT240 and VT340) have
  977.  *  a color palette which is available under the graphics modes.
  978.  *  Further, a foreign terminal could also change color registers.
  979.  *
  980.  *  Nothing returned
  981.  ***/
  982. spal()
  983. {
  984.     /* Nothing */
  985. }
  986.  
  987. #endif /* VMSVT */
  988.  
  989. #if TYPEAH
  990. /***
  991.  *  typahead  -  Check for pending input
  992.  *
  993.  *  typahead check the input buffer for pending input.  If input exists
  994.  *  TRUE is returned.  This routine is used mostly by the display
  995.  *  update routine to avoid redrawing the entire display when it
  996.  *  doesn't need to do so.
  997.  *
  998.  *  Returns:  boolean.
  999.  ***/
  1000. int typahead()
  1001. {
  1002.     int status;
  1003.     struct iosb io;
  1004.     struct tahd tbuf;
  1005.  
  1006.     /* Check for buffered characters */
  1007.     if (inbufh != inbuft)
  1008.         return TRUE;
  1009.  
  1010.     /* Call to system for character count */
  1011.     status = SYS$QIOW(1, channel, IO$_SENSEMODE | IO$M_TYPEAHDCNT,
  1012.         &io, 0, 0, &tbuf, sizeof(tbuf), 0, 0, 0, 0);
  1013.     if (FAILURE(status) || FAILURE(io.i_cond))
  1014.         return FALSE;
  1015.     return tbuf.t_count;
  1016. }
  1017. #endif /* TYPEAH */
  1018.  
  1019. /***
  1020.  *  vmsdcl  -  Execute or invoke a DCL
  1021.  *
  1022.  *  vmsdcl without an argument will invoke a new DCL as a new process
  1023.  *  and attach to it.  When the DCL returns, emacs will regain control.
  1024.  *  With an argument, the DCL starts and begins executing the command
  1025.  *  line.
  1026.  *
  1027.  *  Returns:  status.
  1028.  ***/
  1029. int vmsdcl(command)
  1030. char * command;                /* Command to execute        */
  1031. {
  1032.     int result, status;
  1033.     struct dsc$descriptor desc, * dp;
  1034.     
  1035.     /* Set up descriptor */
  1036.     if (command) {
  1037.         desc.dsc$a_pointer = command;
  1038.         desc.dsc$w_length = strlen(command);
  1039.         desc.dsc$b_dtype = DSC$K_DTYPE_T;
  1040.         desc.dsc$b_class = DSC$K_CLASS_S;
  1041.         dp = &desc;
  1042.     } else 
  1043.         dp = NULL;
  1044.     
  1045.     /* Turn off raw input */
  1046.     vmsstty(&oldmode);
  1047.  
  1048.     /* Call DCL */
  1049.     status = LIB$SPAWN(dp, 0, 0, 0, 0, 0, &result, 0, 0, 0);
  1050.  
  1051.     /* Return to raw input */
  1052.     vmsstty(&newmode);
  1053.     
  1054.     /* Return status */
  1055.     return SUCCESS(status) && SUCCESS(result);
  1056. }        
  1057.  
  1058. /***
  1059.  *  spawncli  -  Spawn a new DCL
  1060.  *
  1061.  *  spawncli reliquishes control of the terminal and passes it on to
  1062.  *  a newly created DCL process.  When the DCL process finishes, the
  1063.  *  screen is redrawen and emacs regains control.
  1064.  *
  1065.  *  Returns:  status
  1066.  ***/
  1067. int spawncli(flag, num)
  1068. int flag;                /* TRUE if default        */
  1069. int num;                /* Numerical argument        */
  1070. {
  1071.     /* Restrict usage */
  1072.     if (restflag)
  1073.         return resterr();
  1074.         
  1075.     /* Move to last line and announce */
  1076.     vmsmove(term.t_nrow, 0);
  1077.     vmsputs(TEXT199);
  1078. /*              "[Starting DCL]\r\n" */
  1079.     vmsflush();
  1080.  
  1081.     /* Redraw screen on return */    
  1082.     sgarbf = TRUE;
  1083.     
  1084.     /* Start command */
  1085.     return vmsdcl(NULL);
  1086. }
  1087.  
  1088. /***
  1089.  *  spawn  -  Spawn a command
  1090.  *
  1091.  *  spawncli reliquishes control of the terminal and passes it on to
  1092.  *  a newly created DCL process.  When the DCL process finishes, the
  1093.  *  screen is redrawen and emacs regains control.
  1094.  *
  1095.  *  Returns:  status
  1096.  ***/
  1097. int spawn(flag, num)
  1098. int flag;                /* TRUE if default        */
  1099. int num;                /* Numerical argument        */
  1100. {
  1101.     char line[NLINE];
  1102.     int status;
  1103.     
  1104.     /* Restrict usage */
  1105.     if (restflag)
  1106.         return resterr();
  1107.         
  1108.     /* Ask for command */
  1109.     status = mlreply("!", line, sizeof(line));
  1110.     if (status != TRUE)
  1111.         return status;
  1112.         
  1113.     /* Move to last line and announce */
  1114.     vmsmove(term.t_nrow, 0);
  1115.     vmsputs(TEXT200);
  1116. /*              "[Calling DCL]\r\n" */
  1117.     vmsflush();
  1118.     
  1119.     /* Run command */
  1120.     status = vmsdcl(line);
  1121.     
  1122.     /* Wait for conformation */
  1123.     vmsputs(TEXT6);
  1124. /*              "\r\n\n[END]" */
  1125.     vmsflush();
  1126.     vmsgchar();
  1127.  
  1128.     /* Redraw screen on return */    
  1129.     sgarbf = TRUE;
  1130.     return status;
  1131. }
  1132.  
  1133. /***
  1134.  *  execprg  -  Execute a program without using command interpretter
  1135.  *
  1136.  *  execprg is the same as spawn because there is no reasonable way
  1137.  *  of avoiding the command interpretter.  This routine is mostly for
  1138.  *  smaller systems.
  1139.  *
  1140.  *  Returns:  status
  1141.  ***/
  1142. int execprg(flag, num)
  1143. int flag;                /* TRUE if default        */
  1144. int num;                /* Numerical argument        */
  1145. {
  1146.     return spawn(flag, num);
  1147. }
  1148.  
  1149. /***
  1150.  *  pipecmd   -  Pipe a one line command into a window
  1151.  *
  1152.  *  pipecmd take a single command and places output into a buffer.
  1153.  *  This is accomplished on non-UNIX machines by sending the result
  1154.  *  of the command interpretter into a temporary file, then reading
  1155.  *  the file into the buffer.
  1156.  *
  1157.  *  This command is not implemented current, but could be implemented
  1158.  *  and will be once I get some manuals.
  1159.  *
  1160.  *  Returns:  status
  1161.  ***/
  1162. int pipecmd(flag, num)
  1163. int flag;                /* TRUE if default        */
  1164. int num;                /* Numerical argument        */
  1165. {
  1166.     mlwrite(TEXT201);
  1167. /*              "[Not available yet under VMS]" */
  1168.     return FALSE;
  1169. }
  1170.  
  1171. /***
  1172.  *  filter  -  Filter buffer through an external command
  1173.  *
  1174.  *  filter take a buffer and pipes into a program.  This is accomplished
  1175.  *  under non-UNIX systems by writing the buffer to a temporary  file
  1176.  *  and running the command with the temporary file as input and another
  1177.  *  temporary file as output.  Once the command completes, the buffer
  1178.  *  is replaced by the contents of the second temporary file and
  1179.  *  all temporary files are removed.
  1180.  *
  1181.  *  This command is currently not implemented, but can be implemented
  1182.  *  and will be once I get the manuals.
  1183.  *
  1184.  *  Returns:  status.
  1185.  ***/
  1186. int filter(flag, num)
  1187. int flag;                /* TRUE if default        */
  1188. int num;                /* Numerical argument        */
  1189. {
  1190.     mlwrite(TEXT201);
  1191. /*              "[Not available yet under VMS]" */
  1192.     return FALSE;
  1193. }
  1194.  
  1195. /* return a system dependant string with the current time */
  1196.  
  1197. char *PASCAL NEAR timeset()
  1198.  
  1199. {
  1200.     register char *sp;    /* temp string pointer */
  1201.     char buf[16];        /* time data buffer */
  1202.     extern char *ctime();
  1203.  
  1204.     time(buf);
  1205.     sp = ctime(buf);
  1206.     sp[strlen(sp)-1] = 0;
  1207.     return(sp);
  1208. }
  1209. #else
  1210. vmshello()
  1211. {
  1212. }
  1213. #endif
  1214.